#pragma once
#include <functional>
#include <poll.h>
#include "Sock.hpp"
//读到什么返回时什么
namespace poll_ns
{
    static const uint16_t defaultPort = 8080;
    static const int fdNum = 2048;
    static const int defaultFd = -1;
    static const int bufferNum = 1024;
    static const int timeOut = 1000;//1000ms
    using func_t = std::function<std::string(const std::string)>;//传入读到的数据，返回处理后的数据
    class PollServer
    {
    public:
        PollServer(func_t func, uint16_t port = defaultPort)
            :_port(port)
            ,_listenSocket(-1)
            ,_readFds(nullptr)
            ,_func(func)
        {}
        void InitServer()
        {
            _listenSocket = Sock::Socket();
            Sock::Bind(_listenSocket, _port);
            Sock::Listen(_listenSocket);
            _readFds = new struct pollfd[fdNum];
            for (int i = 0; i < fdNum; ++i)//清空fd数组
            {
                ResetItem(i);
            }
            //将listen套接字添加到数组里
            _readFds[0].fd = _listenSocket;
            _readFds[0].events = POLLIN;//关心读事件
            LogMessage(NORMAL,"create sock success %d", _listenSocket);
        }
        void Start()
        {
            while(1) 
            {
                int n = poll(_readFds, fdNum, timeOut);
                switch(n)
                {
                case 0://超时返回
                    LogMessage(NORMAL, "timeOut...");
                    break;
                case -1://select失败
                    LogMessage(WARNING, "select error, code: %d, err string:%s", errno, strerror(errno));
                    break;
                default://事件就绪
                    //LogMessage(NORMAL, "have event ready");//如果没有把底层的连接取走，那么_listenSocket将一直就绪
                    HandlerReadEvent();
                    break;
                }
            }
        }
        void ListenEvent(int listenSocket)//监听到来事件
        {
            std::string clientIp;
            uint16_t clientPort = -1;
            int sock = Sock::Accept(listenSocket, &clientIp, &clientPort);//accept ==等 + 获取  
            if(sock < 0) 
            {
                return;
            }
            //在数组中寻找新的fd坑位
            int i = 0;
            for(; i < fdNum; ++i)
            {
                if(_readFds[i].fd != defaultFd) continue;
                else break;
            }
            if(i == fdNum)//说明文件描述符被写满了
            {
                LogMessage(WARNING, "Server is full, please wait");
                close(sock);//满载关闭消息
            }
            else
            {
                _readFds[i].fd = sock;
                _readFds[i].events = POLLIN;
                _readFds[i].revents = 0; 
            }
        }
        void Read(int pos)//pos是文件描述符在数组中的位置,代表哪个文件描述符就绪了
        {
            //1、读取request（这样读取存在问题）
            char buffer[bufferNum];
            ssize_t s = recv(_readFds[pos].fd, buffer, sizeof(buffer)-1, 0);
            if(s > 0)
            {
                buffer[s] = 0;
                LogMessage(NORMAL, "client# %s", buffer);
            }
            else if(0 == s)//连接关闭
            {
                close(_readFds[pos].fd);//close之后，需要在所维护的数组中去掉对应的fd
                ResetItem(pos);
                LogMessage(NORMAL, "client quit");
                return ;
            }
            else//读取失败
            {
                close(_readFds[pos].fd);//close之后，需要在所维护的数组中去掉对应的fd
                ResetItem(pos);
                LogMessage(ERROR, "read fail%s", strerror(errno));
                return ;
            }
            //2、处理request
            std::string response = _func(buffer);
            //3、返回response
            //写事件，有问题的，需要重新维护一个写就绪的文件描述符数组
            write(_readFds[pos].fd, response.c_str(), response.size());
        }
        void ResetItem(int resetIndex)
        {
            _readFds[resetIndex].fd =defaultFd;
            _readFds[resetIndex].events = 0;
            _readFds[resetIndex].revents = 0;
        }
        void HandlerReadEvent()
        {
            for(int i = 0; i < fdNum; ++i)
            {
                //过滤掉空的fd
                if(_readFds[i].fd == defaultFd) continue;
                //如果事件的读未被关心，跳过本轮循环
                if(!(_readFds[i].events & POLLIN)) continue;
                //但是正常的fd不一定就绪
                if(_readFds[i].fd == _listenSocket && (_readFds[i].revents & POLLIN))//如果_listenSocket在rfds集合里
                {
                    ListenEvent(_listenSocket);//监听事件
                }
                else if(_readFds[i].revents & POLLIN)//其他读事件就绪
                {
                    Read(i);//读取事件
                } 
                else
                {}
            }
        }
        ~PollServer()
        {
            if(_readFds)
            {
                for(int i = 0; i < fdNum; ++i)
                {
                    if(_readFds[i].fd != defaultFd)
                    {
                        close(_readFds[i].fd);
                    }
                }
                delete[] _readFds;
            }
        }
    private:
        uint16_t _port;
        int _listenSocket;
        struct pollfd* _readFds;//读文件事件poll的结构体
        func_t _func;
    };
}